package com.roger.tool.volley;

import java.util.Map;

import org.json.JSONObject;

import android.content.Context;

import com.android.volley.AuthFailureError;
import com.android.volley.Request.Method;
import com.android.volley.RequestQueue;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

/**
 * @author lch
 * @version Create time：2017-3-6
 * @类说明：使用Volley的Http网络请求封装
 */
public class VolleyRequest {

	private static final String REQUEST_TAG = "request_tag";

	private static VolleyRequest mVolleyHttpRequest;

	private RequestQueue mRequestQueue;

	/**
	 * 一般而言，网络请求队列都是整个APP内使用的全局性对象
	 * 
	 * @param pContext
	 * @return VolleyHttpRequest
	 */
	public static VolleyRequest getInstance(Context pContext) {
		if (mVolleyHttpRequest == null) {
			synchronized (VolleyRequest.class) {
				// 用 Application 里的 Context
				mVolleyHttpRequest = new VolleyRequest(pContext.getApplicationContext());
			}
		}
		return mVolleyHttpRequest;
	}

	private VolleyRequest(final Context pContext) {
		this.mRequestQueue = Volley.newRequestQueue(pContext);

	}

	// ============================================================
	// 简化单例请求,供外部调用
	// ============================================================
	
	/**
	 * 方式为 get 的 ByteArrayRequest 请求
	 * 
	 * @param url
	 *            请求url
	 * @param pParams
	 *            get 参数（无参时传null或者用另外一个不带参数的方法），会 加在 url 后面 ? = & 分割
	 * @param pByteArrayHttpListener
	 */
	public static void sendGetByteArrayRequest(final Context pContext,final String url, final Map<String, String> pParams,
			final IByteArrayHttpListener pByteArrayHttpListener) {
		VolleyRequest.getInstance(pContext).sendGetByteArrayRequest(url, pParams, pByteArrayHttpListener);
	}
	
	/**
	 * 方式为 get 的 ByteArrayRequest 请求
	 * 
	 * @param url
	 *            get 请求url，如需传参 也放在此url后面,如：www.baidu.com?user=roger&id=123
	 * @param pByteArrayHttpListener
	 *            请求结果监听
	 */
	public static void sendGetByteArrayRequest(final Context pContext,final String url, final IByteArrayHttpListener pByteArrayHttpListener) {
		VolleyRequest.getInstance(pContext).sendGetByteArrayRequest(url, pByteArrayHttpListener);
	}
	
	/**
	 * 方式为 Post 的 ByteArray 请求
	 * 
	 * @param url
	 *            Post请求url
	 * @param pParams
	 *            post请求所带参数(无需传参时填null)，将会转变为 "="、"&"形式分割：如：user=roger&id=123
	 * @param pStringHttpListener
	 *            请求结果监听
	 */
	public static void sendPostByteArrayRequest(final Context pContext,final String url, final Map<String, String> pParams,
			final IByteArrayHttpListener pByteArrayHttpListener) {
		VolleyRequest.getInstance(pContext).sendPostByteArrayRequest(url, pParams, pByteArrayHttpListener);
	}
	
	// ============================================================
	
	/**
	 * 方式为 get 的 StringRequest 请求
	 * 
	 * @param url
	 *            请求url
	 * @param pParams
	 *            get 参数（无参时传null或者用另外一个不带参数的方法），会 加在 url 后面 ? = & 分割
	 * @param pStringHttpListener
	 */
	public static void sendGetStringRequest(final Context pContext, final String url, final Map<String, String> pParams,
			final IStringHttpListener pStringHttpListener) {
		VolleyRequest.getInstance(pContext).sendGetStringRequest(url, pParams, pStringHttpListener);
	}

	/**
	 * 方式为 get 的 StringRequest 请求
	 * 
	 * @param url
	 *            get 请求url，如需传参 也放在此url后面,如：www.baidu.com?user=roger&id=123
	 * @param pStringHttpListener
	 *            请求结果监听
	 */
	public static void sendGetStringRequest(final Context pContext, final String url,
			final IStringHttpListener pStringHttpListener) {
		VolleyRequest.getInstance(pContext).sendGetStringRequest(url, pStringHttpListener);
	}

	/**
	 * 方式为 Post 的 StringRequest 请求
	 * 
	 * @param url
	 *            Post请求url
	 * @param pParams
	 *            post请求所带参数(无需传参时填null)，将会转变为 "="、"&"形式分割：如：user=roger&id=123
	 * @param pStringHttpListener
	 *            请求结果监听
	 */
	public static void sendPostStringRequest(final Context pContext, final String url, final Map<String, String> pParams,
			final IStringHttpListener pStringHttpListener) {
		VolleyRequest.getInstance(pContext).sendPostStringRequest(url, pParams, pStringHttpListener);
	}
	
	// ============================================================

	/**
	 * 方式为 get 的 JsonObjectRequest 请求
	 * 
	 * @param url
	 *            get 请求url(不含参数),参数放下面的 pParams
	 * @param pParams
	 *            请求所带参数(无需传参时填null,或者用另外一个不带参数的方法)
	 * @param pJsonObjectHttpListener
	 *            请求结果监听
	 */
	public static void sendGetJsonObjectRequest(final Context pContext, final String url, final Map<String, String> pParams,
			final IJsonObjectHttpListener pJsonObjectHttpListener) {
		VolleyRequest.getInstance(pContext).sendGetJsonObjectRequest(url, pParams, pJsonObjectHttpListener);
	}

	/**
	 * 方式为 get 的 JsonObjectRequest 请求
	 * 
	 * @param url
	 *            get 请求url，如需传参 也放在此url后面
	 * @param pJsonObjectHttpListener
	 *            请求结果监听
	 */
	public static void sendGetJsonObjectRequest(final Context pContext, final String url,
			final IJsonObjectHttpListener pJsonObjectHttpListener) {
		VolleyRequest.getInstance(pContext).sendGetJsonObjectRequest(url, pJsonObjectHttpListener);
	}

	/**
	 * 方式为 Post 的 JsonObjectRequest 请求
	 * 
	 * @param url
	 *            请求 url
	 * @param pParams
	 *            post请求所带参数(无需传参时填null)，将会转变为 JSONObject toString形式
	 * @param pJsonObjectHttpListener
	 *            请求结果监听
	 */
	public static void sendPostJsonObjectRequest(final Context pContext, final String url, final Map<String, String> pParams,
			final IJsonObjectHttpListener pJsonObjectHttpListener) {
		VolleyRequest.getInstance(pContext).sendPostJsonObjectRequest(url, pParams, pJsonObjectHttpListener);
	}
	
	// ============================================================

	/**
	 * 取消这个队列里的所有请求 游戏退出时调用，否则在游戏退出后可能还有网络请求中，浪费 cpu 资源，还有可能引起 crash
	 */
	public static void stopRequest(final Context pContext) {
		VolleyRequest.getInstance(pContext).stopRequest();
	}

	// ============================================================
	// ByteArrayRequest
	// ============================================================

	/**
	 * 方式为 get 的 ByteArrayRequest 请求
	 * 
	 * @param url
	 *            请求url
	 * @param pParams
	 *            get 参数（无参时传null或者用另外一个不带参数的方法），会 加在 url 后面 ? = & 分割
	 * @param pByteArrayHttpListener
	 */
	public void sendGetByteArrayRequest(final String url, final Map<String, String> pParams,
			final IByteArrayHttpListener pByteArrayHttpListener) {
		String paramRequest = "";
		if (pParams != null && !pParams.isEmpty()) {
			// "=" "&" 分割的参数形式,并对 key、value UTF-8 URLEncoder
			paramRequest = HttpUtils.format(pParams);
		}

		StringBuilder urlSb = new StringBuilder(url);
		if (paramRequest != null && paramRequest.length() > 0) {
			urlSb.append("?");
			urlSb.append(paramRequest);
		}

		this.sendGetByteArrayRequest(urlSb.toString(), pByteArrayHttpListener);
	}

	/**
	 * 方式为 get 的 ByteArrayRequest 请求
	 * 
	 * @param url
	 *            get 请求url，如需传参 也放在此url后面,如：www.baidu.com?user=roger&id=123
	 * @param pByteArrayHttpListener
	 *            请求结果监听
	 */
	public void sendGetByteArrayRequest(final String url, final IByteArrayHttpListener pByteArrayHttpListener) {

		ByteArrayRequest byteArrayRequest = new ByteArrayRequest(Method.GET, url, new Listener<byte[]>() {

			@Override
			public void onResponse(byte[] response) {
				if (pByteArrayHttpListener != null) {
					pByteArrayHttpListener.onResponse(response);
				}
			}
		}, new ErrorListener() {

			@Override
			public void onErrorResponse(VolleyError error) {
				if (pByteArrayHttpListener != null) {
					pByteArrayHttpListener.onErrorResponse(error);
				}
			}
		});

		byteArrayRequest.setTag(REQUEST_TAG);
		mRequestQueue.add(byteArrayRequest);
	}

	/**
	 * 方式为 Post 的 ByteArray 请求
	 * 
	 * @param url
	 *            Post请求url
	 * @param pParams
	 *            post请求所带参数(无需传参时填null)，将会转变为 "="、"&"形式分割：如：user=roger&id=123
	 * @param pStringHttpListener
	 *            请求结果监听
	 */
	public void sendPostByteArrayRequest(final String url, final Map<String, String> pParams,
			final IByteArrayHttpListener pByteArrayHttpListener) {

		ByteArrayRequest byteArrayRequest = new ByteArrayRequest(Method.POST, url, new Listener<byte[]>() {

			@Override
			public void onResponse(byte[] response) {

				if (pByteArrayHttpListener != null) {
					pByteArrayHttpListener.onResponse(response);
				}

			}
		}, new ErrorListener() {

			@Override
			public void onErrorResponse(VolleyError error) {
				if (pByteArrayHttpListener != null) {
					pByteArrayHttpListener.onErrorResponse(error);
				}
			}
		})

		{
			@Override
			protected Map<String, String> getParams() throws AuthFailureError {
				// post 请求时会调用此方法获取参数,JsonRequest 由于 重写了 getBody，因此不在此
				// getParams()传参。

				return pParams;
			}
		};

		byteArrayRequest.setTag(REQUEST_TAG);
		mRequestQueue.add(byteArrayRequest);
	}

	// ============================================================
	// StringRequest
	// ============================================================
	/**
	 * 方式为 get 的 StringRequest 请求
	 * 
	 * @param url
	 *            请求url
	 * @param pParams
	 *            get 参数（无参时传null或者用另外一个不带参数的方法），会 加在 url 后面 ? = & 分割
	 * @param pStringHttpListener
	 */
	public void sendGetStringRequest(final String url, final Map<String, String> pParams,
			final IStringHttpListener pStringHttpListener) {
		String paramRequest = "";
		if (pParams != null && !pParams.isEmpty()) {
			// "=" "&" 分割的参数形式,并对 key、value UTF-8 URLEncoder
			paramRequest = HttpUtils.format(pParams);
		}

		StringBuilder urlSb = new StringBuilder(url);
		if (paramRequest != null && paramRequest.length() > 0) {
			urlSb.append("?");
			urlSb.append(paramRequest);
		}

		this.sendGetStringRequest(urlSb.toString(), pStringHttpListener);
	}

	/**
	 * 方式为 get 的 StringRequest 请求
	 * 
	 * @param url
	 *            get 请求url，如需传参 也放在此url后面,如：www.baidu.com?user=roger&id=123
	 * @param pStringHttpListener
	 *            请求结果监听
	 */
	public void sendGetStringRequest(final String url, final IStringHttpListener pStringHttpListener) {

		StringRequest stringRequest = new StringRequest(Method.GET, url, new Listener<String>() {

			@Override
			public void onResponse(String response) {

				if (pStringHttpListener != null) {
					pStringHttpListener.onResponse(response);
				}

			}
		}, new ErrorListener() {

			@Override
			public void onErrorResponse(VolleyError error) {
				if (pStringHttpListener != null) {
					pStringHttpListener.onErrorResponse(error);
				}
			}
		});

		stringRequest.setTag(REQUEST_TAG);
		mRequestQueue.add(stringRequest);
	}

	/**
	 * 方式为 Post 的 StringRequest 请求
	 * 
	 * @param url
	 *            Post请求url
	 * @param pParams
	 *            post请求所带参数(无需传参时填null)，将会转变为 "="、"&"形式分割：如：user=roger&id=123
	 * @param pStringHttpListener
	 *            请求结果监听
	 */
	public void sendPostStringRequest(final String url, final Map<String, String> pParams,
			final IStringHttpListener pStringHttpListener) {

		StringRequest stringRequest = new StringRequest(Method.POST, url, new Listener<String>() {

			@Override
			public void onResponse(String response) {

				if (pStringHttpListener != null) {
					pStringHttpListener.onResponse(response);
				}

			}
		}, new ErrorListener() {

			@Override
			public void onErrorResponse(VolleyError error) {
				if (pStringHttpListener != null) {
					pStringHttpListener.onErrorResponse(error);
				}
			}
		})

		{
			@Override
			protected Map<String, String> getParams() throws AuthFailureError {
				// post 请求时会调用此方法获取参数,JsonRequest 由于 重写了 getBody，因此不在此
				// getParams()传参。

				return pParams;
			}
		};

		stringRequest.setTag(REQUEST_TAG);
		mRequestQueue.add(stringRequest);
	}

	// ============================================================
	// JsonObjectRequest 若明确返回的数据格式为 JsonObject 推荐使用 JsonObjectRequest
	// ============================================================
	/**
	 * 方式为 get 的 JsonObjectRequest 请求
	 * 
	 * @param url
	 *            get 请求url(不含参数),参数放下面的 pParams
	 * @param pParams
	 *            请求所带参数(无需传参时填null,或者用另外一个不带参数的方法)，会 加在 url 后面 ? = & 分割
	 * @param pJsonObjectHttpListener
	 *            请求结果监听
	 */
	public void sendGetJsonObjectRequest(final String url, final Map<String, String> pParams,
			final IJsonObjectHttpListener pJsonObjectHttpListener) {

		String paramRequest = "";
		if (pParams != null && !pParams.isEmpty()) {
			// "=" "&" 分割的参数形式,并对 key、value UTF-8 URLEncoder
			paramRequest = HttpUtils.format(pParams);
		}

		StringBuilder urlSb = new StringBuilder(url);
		if (paramRequest != null && paramRequest.length() > 0) {
			urlSb.append("?");
			urlSb.append(paramRequest);
		}
		//
		this.sendGetJsonObjectRequest(urlSb.toString(), pJsonObjectHttpListener);
	}

	/**
	 * 方式为 get 的 JsonObjectRequest 请求
	 * 
	 * @param url
	 *            get 请求url，如需传参 也放在此url后面
	 * @param pJsonObjectHttpListener
	 *            请求结果监听
	 */
	public void sendGetJsonObjectRequest(final String url, final IJsonObjectHttpListener pJsonObjectHttpListener) {

		JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Method.GET, url, new Listener<JSONObject>() {

			@Override
			public void onResponse(JSONObject response) {

				if (pJsonObjectHttpListener != null) {
					pJsonObjectHttpListener.onResponse(response);
				}
			}
		}, new ErrorListener() {

			@Override
			public void onErrorResponse(VolleyError error) {
				if (pJsonObjectHttpListener != null) {
					pJsonObjectHttpListener.onErrorResponse(error);
				}
			}
		});

		jsonObjectRequest.setTag(REQUEST_TAG);
		mRequestQueue.add(jsonObjectRequest);
	}

	/**
	 * 方式为 Post 的 JsonObjectRequest 请求
	 * 
	 * @param url
	 *            请求 url
	 * @param pParams
	 *            post请求所带参数(无需传参时填null)，将会转变为 JSONObject toString形式
	 * @param pJsonObjectHttpListener
	 *            请求结果监听
	 */
	public void sendPostJsonObjectRequest(final String url, final Map<String, String> pParams,
			final IJsonObjectHttpListener pJsonObjectHttpListener) {

		JSONObject jsonRequest = null;
		if (pParams != null && !pParams.isEmpty()) {
			try {
				jsonRequest = new JSONObject(pParams);
			} catch (Exception e) {
				jsonRequest = null;
			}
		}

		// jsonRequest传参不仅仅是JSONObject形式，还有 String 形式，有需要再看源码进行扩展
		JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Method.POST, url, jsonRequest, new Listener<JSONObject>() {

			@Override
			public void onResponse(JSONObject response) {
				if (pJsonObjectHttpListener != null) {
					pJsonObjectHttpListener.onResponse(response);
				}
			}
		}, new ErrorListener() {

			@Override
			public void onErrorResponse(VolleyError error) {
				if (pJsonObjectHttpListener != null) {
					pJsonObjectHttpListener.onErrorResponse(error);
				}

			}
		});

		jsonObjectRequest.setTag(REQUEST_TAG);
		mRequestQueue.add(jsonObjectRequest);
	}

	// ============================================================
	// JsonArrayRequest 有需要再去扩展，跟上面的类似
	// ============================================================

	/**
	 * 取消这个队列里的所有请求 游戏退出时调用，否则在游戏退出后可能还有网络请求中，浪费 cpu 资源，还有可能引起 crash
	 */
	public void stopRequest() {

		if (mRequestQueue != null) {
			// 取消 tag 为 request_tag 的所有请求
			mRequestQueue.cancelAll(REQUEST_TAG);
		}
	}

}
